home *** CD-ROM | disk | FTP | other *** search
- page 58,132
- ;****************************************************************
- ;* *
- ;* Digitized Voice Programmer's Toolkit *
- ;* ------------------------------------ *
- ;* *
- ;* Sound Recording Primitives *
- ;* *
- ;* Copyright (c) 1991, Farpoint Software *
- ;* *
- ;****************************************************************
-
- .8086
- .MODEL LARGE
-
- ;**********************************************************************
- ;* *
- ;* Equates *
- ;* *
- ;**********************************************************************
-
- tccount equ 72 ;reload count to produce 16572 Hz
- countmax_18hz equ 910 ;ratio of new timer rate to standard rate
-
- tcaddrc equ 43h ;timer/counter control register address
- tcaddrd0 equ 40h ;timer/counter data register zero (sys clock)
-
- tcmode0a equ 34h ;two-byte mode for system clock timer
- tcmode0b equ 24h ;high-byte mode for system clock timer
-
- tclatchcmd0 equ 00h ;latch command for reading timer 0
-
- ppiaddr equ 61h ;programmable peripheral interface address
-
- kbdonly_mask equ 0FDh ;mask config to allow only keyboard interrupt
- intmaskaddr equ 21h ;address of the interrupt mask register
- kbdint_number equ 9 ;vector number of the keyboard hardware int
-
- ;CPU speed calibration initialization parameters
-
- init_delayctr equ 1024
- init_cal_increment equ 512
- init_cal_passes equ 10
-
- ;**********************************************************************
- ;* *
- ;* Global variables *
- ;* *
- ;**********************************************************************
-
- .DATA
-
- comaddr dw 2ECh
-
- ;CPU speed calibration data
-
- delayctr dw init_delayctr
- cal_increment dw init_cal_increment
- cal_passes dw init_cal_passes
-
- ;keyboard hardware interrupt occurrence flag
-
- keyflag db 0
-
- ;interrupt controller mask save byte
-
- original_mask db 0
-
- comlist dw 3FCh ;needed addresses of all COM ports
- dw 2FCh
- dw 3ECh
- dw 2ECh
-
- ;**********************************************************************
- ;* *
- ;* Code *
- ;* *
- ;**********************************************************************
-
- .CODE
-
- assume ds:DGROUP
-
- ;code-segment storage for keyboard interrupt chain vector
-
- original_kbdint_vec dd 0
-
- ;**********************************************************************
- ;* Keyboard Hardware Interrupt Intercept Routine *
- ;**********************************************************************
-
- ;This routine sets the "keyflag" variable to 1 whenever a keyboard
- ; interrupt occurs.
-
- kbdint proc far
-
- push ds
- push ax
- mov ax,DGROUP
- mov ds,ax
- mov keyflag,1
- pop ax
- pop ds
- jmp dword ptr cs:original_kbdint_vec
-
- kbdint endp
-
- ;**********************************************************************
- ;* Obtain available memory figure from DOS *
- ;**********************************************************************
-
- ;This routine returns a dword indicating the number of bytes of memory
- ; available for allocation from DOS.
-
- public GETMEMAVAIL
-
- GETMEMAVAIL proc far
-
- push bp
- mov bp,sp
-
- mov bx,0FFFFh
- mov ah,48h
- int 21h
- sub bx,16
- jc gma_none
- sub dx,dx
- mov ax,bx
- mov cx,4
- gma_dshift:
- shl ax,1
- rcl dx,1
- loop gma_dshift
-
- gma_exit:
- pop bp
- ret
-
- gma_none:
- sub ax,ax
- sub dx,dx
- jmp gma_exit
-
- GETMEMAVAIL endp
-
- ;**********************************************************************
- ;* Calibrated software delay routine *
- ;**********************************************************************
-
- ;lots of nops
-
- rdelay proc near
-
- db init_delayctr dup (90h)
- ret ;starting delay value
- db (init_delayctr-1) dup (90h)
- ret ;should never actually be executed
-
- rdelay endp
-
- ;**********************************************************************
- ;* Set Calibration Constant *
- ;* *
- ;* This call simply sets the calibration constant to the *
- ;* value specified in the parameter. *
- ;**********************************************************************
-
- ;Accepts the following parameters with PASCAL parameter-passing convention:
-
- ;Position Size Description
- ;-------- ---- -----------
- ; 1 2 The calibration constant to be set.
-
- ;There is no return value.
-
- rsc_parm1 equ [bp+6] ;length = 2
-
- rsc_parmlength equ 2
-
- public RSETCAL
-
- RSETCAL proc far
-
- push bp
- mov bp,sp
-
- ;in case this routine has been called before, erase the "ret" instruction
- ; that was placed in the delay routine
-
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],90h ;this is a "nop" instruction
-
- ;get the new delay parameter
-
- mov ax,rsc_parm1
- mov delayctr,ax
-
- ;insert a "ret" instruction at the new location in the delay routine
-
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
-
- pop bp
- ret rsc_parmlength
-
- RSETCAL endp
-
- ;**********************************************************************
- ;* Calibration procedure *
- ;* *
- ;* This routine must be called once before any calls are made *
- ;* to the recording routine. It measures the CPU execution *
- ;* speed and saves compensation values. *
- ;**********************************************************************
-
- ;There are no entry parameters.
-
- ;The return value is a double word, defined as follows:
-
- ;Return value low word Meaning
- ;--------------------- -------
- ; 0 success
- ; 1 this CPU is too slow to accomplish
- ; normal-speed playback
- ; 2 operation not possible under Windows
- ; in "Enhanced" mode
-
- ;The return value high word is the actual speed calibration constant
- ; for this computer
-
- cal_temp1 equ [bp-2] ;length = 2
- cal_temp2 equ [bp-4] ;length = 2
-
- cal_locallength equ 4
-
- public RCALIBRATE
-
- RCALIBRATE proc far
-
- push bp
- mov bp,sp
- sub sp,cal_locallength
- push si
-
- ;test for the "Enhanced Mode Windows" environment
-
- mov ax,1600h
- int 2Fh
- cmp al,00h
- je cal_no_enh_win
- cmp al,80h
- je cal_no_enh_win
- mov delayctr,1
- mov ax,2
- jmp cal_exit
- cal_no_enh_win:
-
- ;in case this routine has been called before, erase the "ret" instruction
- ; that was placed in the delay routine
-
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],90h ;this is a "nop" instruction
-
- ;initialize parameters
-
- mov delayctr,init_delayctr
- mov cal_increment,init_cal_increment
- mov cal_passes,init_cal_passes
-
- ;insert a "ret" instruction into the starting location in the delay routine
-
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
-
- ;no interrupts until we are through calibrating
-
- cli
-
- ;write the standard setup to timer zero
-
- mov al,tcmode0a
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- mov al,0
- out tcaddrd0,al
- jmp short $+2
- jmp short $+2
- out tcaddrd0,al
- jmp short $+2
- jmp short $+2
-
- ;set timer zero to high-byte mode
-
- mov al,tcmode0b
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- mov al,0
- out tcaddrd0,al
- jmp short $+2
- jmp short $+2
-
- ;use a "dummy" port address
-
- mov dx,comaddr
-
- ;initialize loop count
-
- cal_zerocnt:
- sub cx,cx
- mov word ptr cal_temp1,0
- mov word ptr cal_temp2,0
- mov keyflag,0
-
- ;synchronize to timer tick
-
- mov ah,0
- mov al,tclatchcmd0
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- in al,tcaddrd0
- jmp short $+2
- jmp short $+2
- mov si,ax
- cal_sync:
- mov al,tclatchcmd0
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- in al,tcaddrd0
- jmp short $+2
- cmp ax,si
- mov si,ax
- jbe cal_sync
-
- ;calibration loop
-
- cal_dummyloop:
- mov al,01h
- out dx,al
- jmp short $+2
- jmp short $+2
- add dx,2
- in al,dx
- shr al,1
- shr al,1
- shr al,1
- shr al,1
- mov ah,al
- sub dx,2
- mov al,00h
- out dx,al
- jmp short $+2
- jmp short $+2
- add dx,2
- in al,dx
- and al,0F0h
- or ah,al
- mov al,02h
- sub dx,2
- out dx,al
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- mov al,00h
- out dx,al
- inc cx
- jnz cal_countbytes
- cal_countbytes:
- inc word ptr cal_temp2
- jnz cal_dummydelay
- inc word ptr cal_temp1
- cal_dummydelay:
- call rdelay
- inc dx
- in al,dx
- dec dx
- test al,00h ;dummy test for end of recording
- jnz cal_checktime
- cmp keyflag,0
- jne cal_checktime
- cal_checktime:
- mov al,tclatchcmd0
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- in al,tcaddrd0
- sub ah,ah
- cmp ax,si
- mov si,ax
- jbe cal_dummyloop
-
- ;kill the old "ret" instruction in the delay routine
-
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],90h ;this is a "nop" instruction
-
- ;adjust delay counter
-
- mov ax,cal_increment
- shr cal_increment,1
- cmp cx,countmax_18hz
- je cal_setret
- jb cal_makefaster
- add delayctr,ax
- jmp cal_setret
- cal_makefaster:
- sub delayctr,ax
- cal_setret: ;here we insert a new return
- lea bx,rdelay
- add bx,delayctr
- mov byte ptr cs:[bx],0C3h ;this is a "ret" instruction
- dec cal_passes
- cmp cal_passes,0
- je cal_restore
- jmp cal_zerocnt
-
- ;repair loss of system timer ticks and restore interrupts
-
- cal_restore:
- mov bx,40h
- mov es,bx
- mov bx,6Ch
- add word ptr es:[bx],init_cal_passes+1
- adc word ptr es:[bx+2],0
- cmp word ptr es:[bx+2],18h
- jb cal_tc_end
- ja cal_tc_midnite
- cmp word ptr es:[bx],0B0h
- jb cal_tc_end
- cal_tc_midnite:
- mov byte ptr es:[bx+4],1
- sub word ptr es:[bx],0B0h
- sbb word ptr es:[bx+2],18h
- cal_tc_end:
- sti
-
- ;determine if CPU is too slow
-
- cal_checkcpu:
- cmp delayctr,1
- je cal_cpuslow
- sub ax,ax
- jmp cal_exit
- cal_cpuslow:
- mov ax,1
- cal_exit:
- mov dx,delayctr
- pop si
- add sp,cal_locallength
- pop bp
- ret
-
- RCALIBRATE endp
-
- ;**********************************************************************
- ;* Record procedure *
- ;**********************************************************************
-
- ;Accepts the following parameters with PASCAL parameter-passing convention:
-
- ;Position Size Description
- ;-------- ---- -----------
- ; 1 4 A far pointer to the memory block used for voice data.
- ; 2 4 A dword indicating the length of the memory block.
- ; 3 2 A word containing the number of the COM port to be used
- ; for input (1 thru 4).
-
- ;The return value is a dword indicating the number of bytes recorded.
- ;A return value of -1L indicates that the COM port was invalid.
-
- ;A full buffer or a break interrupt from the UART stops the recording.
-
- rv_parm1 equ [bp+12] ;length = 4
- rv_parm2hi equ [bp+10] ;length = 2
- rv_parm2lo equ [bp+8] ;length = 2
- rv_parm3 equ [bp+6] ;length = 2
-
- rv_parmlength equ 10
-
- rv_temp1 equ [bp-2] ;length = 2
- rv_temp2 equ [bp-4] ;length = 2
-
- rv_locallength equ 4
-
- public RECORDVOICE
-
- RECORDVOICE proc far
-
- push bp
- mov bp,sp
- sub sp,rv_locallength
- push si
-
- ;set up com port
-
- mov dx,rv_parm3
- cmp dx,1
- jae rv_comhirange
- jmp rv_badcom
- rv_comhirange:
- cmp dx,4
- jbe rv_lookupcomaddress
- jmp rv_badcom
- rv_lookupcomaddress:
- dec dx
- shl dx,1
- lea bx,comlist
- add bx,dx
- mov dx,[bx]
- mov comaddr,dx
-
- sub dx,4
- in al,dx
- jmp short $+2
- jmp short $+2
- in al,dx
- jmp short $+2
- jmp short $+2
- in al,dx
- jmp short $+2
- jmp short $+2
- add dx,2
- in al,dx
- jmp short $+2
- jmp short $+2
- add dx,3
- in al,dx
- jmp short $+2
- jmp short $+2
- inc dx
- in al,dx
- sub dx,2
-
- ;mask all interrupts except the keyboard
-
- cli
-
- in al,intmaskaddr
- mov original_mask,al
- mov al,kbdonly_mask
- out intmaskaddr,al
-
- ;install the keyboard interrupt intercept routine
-
- sub ax,ax
- mov es,ax
- mov bx,kbdint_number*4
- mov ax,es:[bx]
- mov word ptr cs:original_kbdint_vec,ax
- mov ax,es:[bx+2]
- mov word ptr cs:original_kbdint_vec+2,ax
- lea ax,kbdint
- mov es:[bx],ax
- mov ax,cs
- mov es:[bx+2],ax
-
- sti
-
- ;set up initial conditions
-
- mov word ptr rv_temp1,0
- mov word ptr rv_temp2,0
- mov keyflag,0
- les bx,dword ptr rv_parm1
- mov cx,rv_parm2lo
- mov si,rv_parm2hi
- cmp cx,0
- je rv_recordloop
- inc si
-
- ;recording loop
-
- rv_recordloop:
- mov al,01h
- out dx,al
- jmp short $+2
- jmp short $+2
- add dx,2
- in al,dx
- shr al,1
- shr al,1
- shr al,1
- shr al,1
- mov ah,al
- sub dx,2
- mov al,00h
- out dx,al
- jmp short $+2
- jmp short $+2
- add dx,2
- in al,dx
- and al,0F0h
- or ah,al
- mov al,02h
- sub dx,2
- out dx,al
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- jmp short $+2
- mov al,00h
- out dx,al
- mov es:[bx],ah
- inc bx
- jnz rv_countbytes
- mov ax,es
- add ax,1000h
- mov es,ax
- rv_countbytes:
- inc word ptr rv_temp2
- jnz rv_delay
- inc word ptr rv_temp1
- rv_delay:
- call rdelay
- inc dx
- in al,dx
- dec dx
- test al,10h ;test for end of recording
- jnz rv_stop
- cmp keyflag,0
- jne rv_stop
- mov al,tclatchcmd0
- out tcaddrc,al
- jmp short $+2
- jmp short $+2
- in al,tcaddrd0
- sub ah,ah
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- loop rv_recordloop
- dec si
- jnz rv_recordloop
- rv_stop:
-
- ;remove the keyboard interrupt intercept routine
-
- cli
-
- sub ax,ax
- mov es,ax
- mov bx,kbdint_number*4
- mov ax,word ptr cs:original_kbdint_vec
- mov es:[bx],ax
- mov ax,word ptr cs:original_kbdint_vec+2
- mov es:[bx+2],ax
-
- ;restore the original interrupt mask
-
- mov al,original_mask
- out intmaskaddr,al
-
- sti
-
- ;compensate for lost timer ticks
-
- mov dx,rv_parm2hi
- mov ax,rv_parm2lo
- mov cx,countmax_18hz
- div cx
- mov bx,40h
- mov es,bx
- mov bx,6Ch
- cli
- add es:[bx],ax
- adc word ptr es:[bx+2],0
- cmp word ptr es:[bx+2],18h
- jb rv_tc_end
- ja rv_tc_midnite
- cmp word ptr es:[bx],0B0h
- jb rv_tc_end
- rv_tc_midnite:
- mov byte ptr es:[bx+4],1
- sub word ptr es:[bx],0B0h
- sbb word ptr es:[bx+2],18h
- rv_tc_end:
- sti
-
- ;set return value
-
- mov dx,rv_temp1
- mov ax,rv_temp2
-
- ;exit
-
- rv_exit:
- pop si
- add sp,rv_locallength
- pop bp
- ret rv_parmlength
-
- ;set return value for COM port out of range
-
- rv_badcom:
- mov dx,0FFFFh
- mov ax,0FFFFh
- jmp rv_exit
-
- RECORDVOICE endp
-
- end
-